function Node(x,y)
{
    this.position = new Position(x,y);
    this.activated = true;
    this.live = true;
    this.r = 5;
}

function Missile(x,y, vx, vy)
{
    this.MAX_VELOCITY = 4;
    this.gravity = 0.08;
    this.radius = 15;
    this.position = null;
    this.velocity = null;
    this.previousPosition = null;

    this.init = function(x,y, vx, vy)
    {
        this.position = new Position(x,y);
        this.velocity = new Position(vx, vy);
        this.previousPosition = new Position(x-vx,y-vy);
    }
    this.update = function()
    {
        this.velocity.y += this.gravity;
        if(this.velocity.y > this.MAX_VELOCITY)
            this.velocity.y = this.MAX_VELOCITY;
        if(this.velocity.y < -this.MAX_VELOCITY)
            this.velocity.y = -this.MAX_VELOCITY;

    	this.position.x += this.velocity.x;
    	this.position.y += this.velocity.y;
    };
}

var ctx;
var ball_img = {'x':30, 'y':124, 'w':56, 'h':56};
var star_img = {'x':0, 'y':0, 'w':88, 'h':83};
var node_img = {'x':131, 'y':114, 'w':22, 'h':22};
var g_particleList = [];
function Game()
{
    this.points = [];
    this.ball = null;
    this.nodeAvailable = false;
    this.node_next = null;
    this.timer_id = 0;
    this.paused = true;
    this.canvas = null;
    this.texture = null;
    this.stars = [];
    this.stars_collected = 0;
    this.add_star = false;
    this.mouseClicked = function(x, y)
    {
        if(this.nodeAvailable)
        {
            var p = g_camera.getAbsolutePos(x, y);
            this.points.push(new Node(p[0], p[1]));
            this.nodeAvailable = false;
        }
    };

    this.getTotalDistance = function()
    {
        var d = 0;
        for(var i=1; i < this.points.length; i++)
        {
            var p1 = this.points[i-1].position;
            var p2 = this.points[i].position;
            d += Math.sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y) *(p1.y-p2.y));
        }
        return d;
    };

    this.mouseMoved = function(x, y)
    {
        this.node_next.position.x = x;
        this.node_next.position.y = y;
    };

    this.pause = function()
    {
        //clearInterval(this.timer_id);
        this.paused = true;
    };

    this.resume = function()
    {
        //timer_id = setInterval(GameUpdate, 1000/60);
        this.paused = false;
    };

    this.gameOver = function()
    {
        this.pause();
        g_gui.showScore();
    };

    this.init = function(canvas)
    {
        this.texture = document.getElementById("texture");
        this.canvas = canvas;
        ctx = canvas.getContext("2d");
        this.stars = [];
        this.stars_collected = 0;
        this.points = [];
        this.points.push(new Node(canvas.width/2,canvas.height-20));
        this.nodeAvailable = true;
        this.node_next = new Node(canvas.width/2,canvas.height/2);
        this.ball = new Missile();		
        this.ball.init(250,20, -1, 0)
            g_camera.pos.x = 0;
        g_camera.pos.y = 0;
        g_camera.target.x = 0;
        g_camera.target.y = 0;
        //this.add_star = true;
        //this.addStar(g_camera.pos);
        g_particleList = [];
        ctx.clearRect(0, 0, g_canvas.width, g_canvas.height);
        //this.resume();
    };
    this.addStar = function(point)
    {
        if(this.add_star)
        {
            //console.log("addingStar At: ", point);
            var star = new Node(RandChoice([50,200,300,400]),point.y+100)
                star.r = 20;
            this.stars.push(star);
            this.add_star = false;
        }
    }    
    this.getScore = function()
    {
        var total_length =  this.getTotalDistance();
        var num_stars = this.stars_collected;
        var num_nodes = this.points.length; 
        //score should be inversly proportional to num nodes.
        //directly proportional to the distance
        //directly proportional to the stars collected.
        return Math.round(num_stars * 200 + total_length);
    }
    this.update = function()
    {
        if(this.paused)
            return;
        if(!g_camera.update())
        {
            this.ball.update();
            this.add_star = true;
        }
        this.checkForShieldIntersection(this.points, this.ball);
        this.checkForStarIntersection(this.stars, this.ball);
        var p = g_camera.getRelativePos(this.ball.position);
        if(this.points.length > 4 && p[1] < this.canvas.height/8 && !this.nodeAvailable)
        {
            //console.log("start Panning");
            var cp = new Position(g_camera.target.x, g_camera.target.y);
            cp.y -=this.canvas.height/2;
            this.addStar(cp);
            g_camera.panTo(cp, 5);
        }

        if(p[1] > this.canvas.height)
        {
            this.gameOver();
        }
        //update the particles
        var tmp = [];
        for(var i in g_particleList)
        {
            g_particleList[i].update();
            if(g_particleList[i].live)
                tmp.push(g_particleList[i]);
        }
        g_particleList = tmp;
    };

    this.render = function()
    {
        if(this.paused)
            return;
        ctx.clearRect(0,0,g_canvas.width, g_canvas.height);
        if(this.nodeAvailable)
            ctx.lineWidth = 2;
        else
            ctx.lineWidth = 1;
        //draw the bouncing ball
        var bp = g_camera.getRelativePos(this.ball.position);
        ctx.drawImage(this.texture, ball_img.x,ball_img.y, ball_img.w, ball_img.h, bp[0]-this.ball.radius, bp[1]-this.ball.radius, 2*this.ball.radius, 2*this.ball.radius);

        ctx.strokeStyle = "rgba(255,255,255,0.4)";
        //drawing the guide line for next point
        var p = g_camera.getRelativePos(this.points[this.points.length-1].position);
        var n;//g_camera.getRelativePos(this.node_next.position);
        ctx.beginPath();
        ctx.moveTo(p[0],p[1]);
        ctx.lineTo(this.node_next.position.x, this.node_next.position.y);
        ctx.stroke();
        //draw the stars
        for(var j = 0, len = this.stars.length; j<len; j++)
        {
            if(g_camera.isInView(this.stars[j].position))
            {
                p = g_camera.getRelativePos(this.stars[j].position);
                var ra = this.stars[j].r;
                ctx.drawImage(this.texture, star_img.x, star_img.y, star_img.w, star_img.h, p[0]-ra, p[1]-ra, 2*ra, 2*ra);
            }
        }
        //draw the first node 
        ctx.lineWidth= 2;
        //draw the prev lines
        for(var j = 0, len = this.points.length; j < len; j++)
        {
            if(g_camera.isInView(this.points[j].position))
            {
                //draw the end points of lines.
                p = g_camera.getRelativePos(this.points[j].position);
                var node = this.points[j];
                ctx.drawImage(this.texture, node_img.x,node_img.y,node_img.w,node_img.h, p[0]-node.r, p[1]-node.r, 2*node.r, 2*node.r);

                //draw the lines.
                if(j > 0)
                {
                    if(!this.points[j-1].live && !this.points[j].live)
                        ctx.strokeStyle = "rgba(255,128,0,0.9)";
                    else
                        ctx.strokeStyle = "rgba(255,255,255,0.4)";

                    p = g_camera.getRelativePos(this.points[j-1].position);
                    n = g_camera.getRelativePos(this.points[j].position);
                    ctx.beginPath();
                    ctx.moveTo(p[0], p[1]);
                    ctx.lineTo(n[0],n[1]);
                    ctx.stroke();
                }
            }
        }
        //render the particles
        for(var i in g_particleList)
            g_particleList[i].draw();
    };
    this.checkForStarIntersection = function(points, ball)
    {
        var npts = [];
        for(var j = 0; j < points.length; j++)
        {
            if(distance(points[j].position, ball.position) < (ball.radius + points[j].r))
            {
                points[j].live = false;
                this.stars_collected += 1;
                AddBlast(points[j].position, "rgb(255,255,255)");
            }
            if(points[j].live && points[j].position.y < (g_camera.pos.y+this.canvas.height))
                npts.push(points[j]);
        }
        this.stars = npts;
    }
    this.checkForShieldIntersection = function(points, missile)
    {
        for(var j = 0, len = points.length; j < len - 1; j++)
        {
            var nodeA = points[j];
            var nodeB = points[j + 1];

            // get all the position info on the line
            // segment ends and the missile
            var x1 = nodeA.position.x;
            var x2 = nodeB.position.x;
            var x3 = missile.position.x;

            var y1 = nodeA.position.y;
            var y2 = nodeB.position.y;
            var y3 = missile.position.y;

            // work out the length of the line and whether
            // or not the missile is potentially intersecting
            // the line
            var d  = Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1));
            var u  = (((x3 - x1) * (x2 - x1)) + ((y3 - y1) * (y2 - y1))) / (d * d);

            // if we know we are in the right segment
            if(u > 0 && u < 1)
            {
                // work out where the intersection
                // point exactly should be
                var ix = x1 + (u*(x2-x1));
                var iy = y1 + (u*(y2-y1));

                // Detail of movement simulation
                var point = missile.position;
                var SHIELD_PROXIMITY_THRESHOLD = missile.radius;

                // check for proximity
                if(Math.sqrt((point.x - ix) * (point.x - ix) + (point.y - iy) * (point.y - iy)) < SHIELD_PROXIMITY_THRESHOLD)
                {
                    // work out our angles
                    var missileToLineAngle			= Math.atan2(missile.velocity.y, missile.velocity.x);
                    var normal 						= Math.atan2((y1 - y2), (x1 - x2)) - Math.PI/2;
                    var missileToNormalAngle		= normal - missileToLineAngle;
                    // now work out the exit angle
                    // for the missile after the collision
                    var newMissileToNormalAngle 	= normal + missileToNormalAngle;
                    // update the missile's velocity and position
                    missile.velocity.x				= -Math.cos(newMissileToNormalAngle) * missile.MAX_VELOCITY;
                    missile.velocity.y 				= -Math.sin(newMissileToNormalAngle) * missile.MAX_VELOCITY;
                    missile.update();

                    AddBlast(new Position(ix,iy), "rgb(255,128,0)");
                    if(!points[j].live && !points[j+1].live)
                    {
                        this.gameOver();
                    }
                    points[j].live = false;
                    points[j+1].live = false;
                    this.nodeAvailable = true;
                    break;
                }
            }
        }
    };
}



